package edu.fyvtc.javaweb.demo.aspect;

import edu.fyvtc.javaweb.demo.common.DemoResult;
import edu.fyvtc.javaweb.demo.model.House;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;

//@Aspect表示这是一个切面类
//@Component表示这个类加入Spring Bean管理
//@Slf4j时lombok中的一个注解
//用于编译时在ClassworkAspect类中插入一个log属性，代码中可以直接使用log
//logs记录日志的功能由logback实现，Spring boot已默认依赖了logback
//logback的配置文件为  resources/logback.xml
@Aspect
@Component
@Slf4j
public class LogAspect {

    //1. 插入方法的Pointcut
    //execution 指定了返回类型，方法名，方法入参
    @Pointcut("execution (edu.fyvtc.javaweb.demo.common.DemoResult edu.fyvtc.javaweb.demo.controller.PublishController.insert(edu.fyvtc.javaweb.demo.model.House))")
    public void insertPointcut() {

    }

    //2. 更新方法的Pointcut
    //execution 指定了返回类型，方法名，方法入参
    @Pointcut("execution (edu.fyvtc.javaweb.demo.common.DemoResult edu.fyvtc.javaweb.demo.controller.PublishController.update(edu.fyvtc.javaweb.demo.model.House))")
    public void updatePointcut() {

    }

    //3. 整个PublishController类的Pointcut
    //within 指定了类名
    @Pointcut("within(edu.fyvtc.javaweb.demo.controller.PublishController)")
    public void publishPointcut() {

    }

    //4. 属于publishPointcut() 但不属于insertPointcut() 和 updatePointcut()的Pointcut
    //Pointcut可以进行逻辑运算，生成新的Pointcut
    @Pointcut("publishPointcut() && !insertPointcut() && !updatePointcut()")
    public void publishOtherPointcut() {

    }

    //5. 整个HomeController类的Pointcut
    //within 指定了类名
    @Pointcut("within(edu.fyvtc.javaweb.demo.controller.HomeController)")
    public void homePointcut() {

    }



    //insert方法执行前，先设置入参house一些属性的值，然后再执行
    //
    @SneakyThrows
    @Around("insertPointcut()")
    public DemoResult insertAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        Object[] args = proceedingJoinPoint.getArgs();
        House house = (House) args[0];
        if (house.getCreator() == null || house.getCreator().isEmpty()) {
            house.setCreator("黑无常");
        }

        log.info("开始运行PublishController.insert方法，入参： {}", Arrays.toString(args));
        DemoResult result = (DemoResult) proceedingJoinPoint.proceed();
        log.info("结束执行PublishController.insert方法，返回： {}", result);
        return result;
    }

    @SneakyThrows
    @Around("updatePointcut()")
    public Object updateAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        Object[] args = proceedingJoinPoint.getArgs();
        House house = (House) args[0];
        if (house.getCreator() == null || house.getCreator().isEmpty()) {
            house.setCreator("黑无常");
        }
        if (house.getModifier() == null || house.getModifier().isEmpty()) {
            house.setModifier("白无常");
        }

        log.info("开始运行PublishController.update方法，入参： {}", Arrays.toString(args));
        DemoResult result = (DemoResult) proceedingJoinPoint.proceed();
        log.info("结束执行PublishController.update方法，返回： {}", result);
        return result;
    }

    @SneakyThrows
    @Around("publishOtherPointcut()")
    public Object publishOtherAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        Object[] args = proceedingJoinPoint.getArgs();
        String methodName = proceedingJoinPoint.getSignature().getName();

        log.info("开始运行PublishController.{}方法，入参： {}", methodName, Arrays.toString(args));
        DemoResult result = (DemoResult) proceedingJoinPoint.proceed();
        log.info("结束执行PublishController.{}方法，返回： {}", methodName, result);
        return result;

    }

    @Before("homePointcut()")
    public void beforeAdvice(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        String methodName = joinPoint.getSignature().getName();
        log.info("开始运行HomeController.{}方法，入参： {}", methodName, Arrays.toString(args));
    }

    @AfterReturning(value = "homePointcut()", returning = "result")
    public void afterAdviceReturn(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        log.info("结束执行HomeController.{}方法，返回： {}", methodName, result);
    }

    @AfterThrowing(value = "homePointcut()", throwing = "t")
    public void afterAdviceThrow(JoinPoint joinPoint, Throwable t) {
        String methodName = joinPoint.getSignature().getName();
        log.error("异常执行HomeController.{}方法", methodName);
        log.debug("异常执行HomeController.{}方法", t.toString());
    }

}
